﻿/*
 * ProjectionUnitTransform
 * 
 * initial implementation : 20.11.2008
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see Petra.Gis.License.txt
 */
using System;
using Petra.Gis.Geometry.Support;


namespace Petra.Gis.ReferenceSystemServices.Transformations
{

  /// <summary>
  /// provides simple projection (2d) unit transformation between exact same coordinate systems
  /// eg. meter to feet
  /// </summary>
  public class MeasureUnitTransform : InversibleTransform
  {

    double _ratio;


    /// <summary>
    /// xaml constr.
    /// </summary>
    public MeasureUnitTransform() 
    {
      Metadata = new Metadata("storage units transformation", "none", -1, "", "", "provides storage unit transformation between exactly same Coordinate systems with different storage units");
    } 





    public MeasureUnitTransform(CoordinateSystem sourceCS, CoordinateSystem targetCS)
      :this(sourceCS, targetCS, false){ }





    public MeasureUnitTransform(CoordinateSystem sourceCS, CoordinateSystem targetCS, bool createInverse)
      : base(sourceCS, targetCS, createInverse)
    {
      validataSourceAndTarget(sourceCS, targetCS);

      Metadata = new Metadata("storage units transformation", "none", -1, "", "", "provides storage unit transformation between exactly same Coordinate systems with different storage units");
    }





    public override CoordinateSystem Source
    {
      get
      {
        return base.Source;
      }
      set
      {
        if (Target != null && value != null)
          validataSourceAndTarget(value, Target);
        
        base.Source = value;
      }
    }





    public override CoordinateSystem Target
    {
      get
      {
        return base.Target;
      }
      set
      {
        if (value != null && Source != null)
          validataSourceAndTarget(Source, value);

        base.Target = value;
      }
    }





    protected override void transform(ICoordinate point)
    {

      point.X *= _ratio;
      point.Y *= _ratio;
    }




    public override CoordStruct Transform(CoordStruct point)
    {

      point.X *= _ratio;
      point.Y *= _ratio;

      return point;
    }






    /// <summary>
    /// this function prevents assignment invalid values to source or target CS
    /// </summary>
    /// <param name="sourceCS"></param>
    /// <param name="targetCS"></param>
    private void validataSourceAndTarget(CoordinateSystem sourceCS, CoordinateSystem targetCS)
    {
      if (sourceCS.GetType() != targetCS.GetType())
        throw new ArgumentException("invalid operation, source and target Coordinate systems are not of same type");

      if (sourceCS.EqualParams(targetCS, CsCompareType.CompareAllParams))
        throw new ArgumentException("invalid operation, source and target Coordinate systems are exactly same");

      //UpdateTransform();
    }





    protected override void updateTransform()
    {
      //if (_sourceCS == null || _targetCS == null)
      //  return;

      //prepare conversion ratio
      if (Source.Unit.GetType() == typeof(DistanceUnit))
        _ratio = ((DistanceUnit)Source.Unit).MetersPerUnit / ((DistanceUnit)Target.Unit).MetersPerUnit;
      else //AngularUnit
        _ratio = ((AngularUnit)Source.Unit).RadiansPerUnit / ((AngularUnit)Target.Unit).RadiansPerUnit;

      if (IsInverse)
        _ratio = 1.0 / _ratio;

    }





    protected override bool graphCompleted()
    {
      //nothing extra to check
      return true;
    }




    public override SRSTransform Inverse()
    {
      return new MeasureUnitTransform(Source, Target, !IsInverse);
    }





    public override Dimension TransformDimension
    {
      get { return Dimension.dim2D; }
    }


  }

}
